export default class DrawGraph{
    constructor(el){
        let $el = el.nodeType == 1 ? el : document.querySelector(el);
        let wrap_w = $el.clientWidth;
        let wrap_h = $el.clientHeight;
        let e_canvas = document.createElement('canvas');
        e_canvas.width = wrap_w;
        e_canvas.height = wrap_h;
        e_canvas.setAttribute('style',`width:${wrap_w}px; height:${wrap_h}px;`)
        e_canvas.onmousemove = e => this.mousemove(e);
        e_canvas.onmouseout = e => this.mousemove(e);
        e_canvas.onclick = e => this.click(e);
        $el.appendChild(e_canvas);
        this.wrap_w = wrap_w;
        this.wrap_h = wrap_h;
        this.$canvas = e_canvas;
        this.$ctx = e_canvas.getContext('2d');
        this.$data = null;
        this.t = null;
        this.onclick = null;
        this.onclick2 = null;
        this.onmouseover = null;
        this.onmouseover2 = null;
    }
    mousemove(e){
        clearTimeout(this.t);
        this.t = setTimeout(() => {
            let {
                offsetX=-10000,
                offsetY=-10000,
            } = e;
            let {
                $canvas
            } = this;
            let selectDataOption = this.getSelectPointInPath(offsetX,offsetY).pop();
            if(selectDataOption){  
                $canvas.style.cursor = "pointer";
                selectDataOption.isEmphasis = true;
                this.drawGraphAll();  
                // this.drawGraphItem({
                //     ...selectDataOption,
                //     emphasis:{
                //         itemStyle:{
                //             ...selectDataOption.emphasis.itemStyle,
                //             backgroundColor:"rgba(0,0,0,0)"
                //         },
                //     }
                // });
                this.onmouseover && this.onmouseover(selectDataOption);
            }else{
                $canvas.style.cursor = "";
                this.onmouseover2 && this.onmouseover2();
            }
        },20)
    }
    click(e){
        clearTimeout(this.t);
        this.t = setTimeout(() => {
            let {
                offsetX,
                offsetY,
            } = e;
            let selectDataOption = this.getSelectPointInPath(offsetX,offsetY).pop();
            if(selectDataOption){
                selectDataOption.isEmphasis = true
                this.drawGraphAll();
                this.onclick && this.onclick(selectDataOption);
            }else{
                this.onclick2 && this.onclick2();
            }
        },30)
    }
    createLinearGradient(x0,y0,x1,y1,addColorStops){
        let grd = this.$ctx.createLinearGradient(x0,y0,x1,y1);
        addColorStops.forEach(addColorStopItem => {
            grd.addColorStop(...addColorStopItem)
        })
        return grd;        
    }
    createRadialGradient(x0,y0,r0,x1,y1,r1,addColorStops){
        let grd = this.$ctx.createRadialGradient(x0,y0,r0,x1,y1,r1);
        addColorStops.forEach(addColorStopItem => {
            grd.addColorStop(...addColorStopItem)
        })
        return grd;
    }
    drawPointPath(coordinates){
        let {
            $ctx,
        } = this;
        $ctx.moveTo(...coordinates[0]);
        coordinates.slice(1).forEach(coordinateItem => {
            $ctx.lineTo(...coordinateItem);
        })
    }
    drawFillText(label){
        let {
            show,
            name,
            x=0,
            y=0,
            fontSize=12,
            color="#ffffff",
        } = label || {};
        if(show !== true || !name) return;
        let {
            $ctx,
        } = this;
        $ctx.font=`${fontSize}px Arial`;
        $ctx.textAlign="center";
        $ctx.fillStyle=color;
        name.split(/\n/).forEach((str, i) => {
            $ctx.fillText(str, x, y + fontSize*i);
        })
    }
    drawStroke(strokeOption){
        let {
            borderWidth=1,
            borderColor="#rgba(0,0,0,0)",
            lineJoin="miter",
            opacity=1,
            shadowColor="",
            shadowBlur=0,
            shadowOffsetY=0,
        } = strokeOption || {};
        let {$ctx} = this;
        $ctx.globalAlpha=opacity;
        $ctx.lineWidth = borderWidth;
        $ctx.lineJoin = lineJoin;
        $ctx.strokeStyle = borderColor;
        $ctx.shadowColor = shadowColor;
        $ctx.shadowBlur = shadowBlur;
        $ctx.shadowOffsetY = shadowOffsetY;
        $ctx.stroke();
    }
    drawFill(fillStyle){
        let {
            backgroundColor = "rgba(0,0,0,0)",
            opacity=1,
        } = fillStyle || {};
        let {$ctx} = this;
        $ctx.globalAlpha=opacity;
        $ctx.fillStyle = backgroundColor;
        $ctx.fill();
    }
    drawGraphItem(optionItem){
        let {
            $ctx,
        } = this;
        let {
            selected,
            isEmphasis,
            coordinates,
            label,
            itemStyle,
            emphasis,
        } = optionItem;
        $ctx.beginPath();
        coordinates.forEach((coordinateItems) => {
            this.drawPointPath(coordinateItems);
        })
        if(selected === true) {
            this.selectStyle(optionItem);
        }else{
            $ctx.save();
            // $ctx.shadowColor="#000";
            // $ctx.shadowColor = optionItem.emphasis.itemStyle.backgroundColor
            // $ctx.translate(0, -60)    
            // $ctx.shadowBlur=25;      
            // $ctx.shadowOffsetY=25;
            this.drawFill({
                ...itemStyle,
                ...(isEmphasis ? emphasis.itemStyle : {}),
            });
            this.drawStroke({
                ...itemStyle,
                ...(isEmphasis ? emphasis.itemStyle : {}),
            });
            this.drawFillText(isEmphasis ? {...label,...emphasis.label} : label); 
            $ctx.restore(); 
        }
        return optionItem;
    }
    drawGraphAll(fn){
        let {
            wrap_w,
            wrap_h,
            $ctx,
            $data
        } = this;
        $ctx.clearRect(0,0,wrap_w,wrap_h);
        let index = $data.findIndex(item => {
            return item.selected;
        })
        $data.push($data[index]);
        $data.splice(index,1);
        $data.forEach((item) => {
            this.drawGraphItem(item);
            fn && fn(item);
        })
    }
    getSelectPointInPath(x,y){
        let {
            $ctx,
            $data,
        } = this;
        let arr = [];
        this.drawGraphAll((item) => {
            item.isEmphasis = false;
            if($ctx.isPointInPath(x,y)) arr.push(item);
        })
        return arr;
    }
    selectStyle(selectDataOption){
        let {
            $canvas,
            $ctx,
        } = this;
        selectDataOption.isEmphasis = true;
        selectDataOption.label.show = false;
        this.drawGraphAll();     
        $ctx.save();
        $ctx.globalCompositeOperation="destination-out";
        this.drawGraphItem({
            ...selectDataOption,
            name:'',
        });   
        $ctx.restore(); 
        $ctx.save();
        $ctx.shadowColor=selectDataOption.emphasis.itemStyle.backgroundColor;
        $ctx.translate(0, -60)    
        $ctx.shadowBlur=0;
        $ctx.shadowOffsetY=20;
        Promise.resolve().then(() => {
            $ctx.save();
            $ctx.translate(-30, -50);
            selectDataOption.label.show = true;   
        })                           
        this.drawGraphItem({
            ...selectDataOption,
            emphasis:{
                itemStyle:{
                    ...selectDataOption.emphasis.itemStyle,
                    // backgroundColor:"rgba(0,0,0,0)"
                },
            }
        });
        $ctx.restore();              
        Promise.resolve().then(() => {
            $ctx.restore();
        })        
    }
    init(option){
        let {
            coordinateData = [],
            label={},
            itemStyle = {},
            emphasis = {},
            data = [],
        } = option;
        let $data = coordinateData.map((item,i) => {
            let {
                name,
                x,
                y,
            } = item; 
            let dataItemOption = data.find((dataItem,dataIndex) => {
                return dataItem.name == name;
            }) || {};
            return {
                ...dataItemOption,
                ...item,
                selected:false,
                isEmphasis:false,
                label:{
                    name,
                    x,
                    y,
                    ...label,
                    ...(dataItemOption.label || {}), 
                },
                itemStyle:{
                    // borderWidth:1,
                    // borderColor:"#ffffff",
                    // backgroundColor:"",
                    ...itemStyle,
                    ...(dataItemOption.itemStyle || {}),  
                },
                emphasis:{
                    ...emphasis,
                    ...(dataItemOption.emphasis || {}),                 
                },
            };
        })
        this.$data = $data;
        this.drawGraphAll();
    }
    [Symbol.toStringTag] = "DrawGraph";
};    